Mobile Development-Using Layout Managers
Hi there
I would like to bring back to mind the advantages of using a layout manager (LM) for your smart device .Net projects.
None of the layout Managers mentioned here are developed by me, I dont have the time to do so, especially, when there are great free solutions on the net.
On full .net framework you have the tablelayout panel where you can place your GUI elements and the elements will be arranged automatically, when the main form is resized.
OK, on smart devices, there will be less form resizing as mostly the forms are full screen by design (QVGA:240×320 or VGA:480×640) . But what happens to your form design, when the user rotates the screen from portrait to landscape orientation?
Sample Code:
public DialogTest2 ()
{
int iWidth=240-26;
int iMaxHeight=320-26-13;
int iLeft=6;
this.Size=new Size(240,320);
TextBox textbox = new TextBox();
textbox.Multiline=true;
textbox.Size=new Size(iWidth,180);
textbox.Top=6;
textbox.Left=iLeft;
Button btnExit=new Button();
btnExit.Text="Back";
btnExit.Click+=new EventHandler(btnExit_Click);
btnExit.Top=iMaxHeight-26;
btnExit.Left=iLeft;
btnExit.Size=new Size(iWidth,26);
btnExit.BackColor=Color.Gray;
Button btnSwitch=new Button();
btnSwitch.Text="Switch";
btnSwitch.Click+=new EventHandler(btnSwitch_Click);
btnSwitch.Top=iMaxHeight-26-26-13;
btnSwitch.Left=iLeft;
btnSwitch.Size=new Size(iWidth,26);
btnSwitch.BackColor=Color.Gray;
this.Controls.Add(textbox);
this.Controls.Add(btnSwitch);
this.Controls.Add(btnExit);
this.BackColor=Color.Aqua;
this.Text="DialogTest";
this.AutoScroll=true;
}
To adjust the positions and sizes of these 3 elements, you would need to change top, left and size property of every element in the forms resize event handler.
Positioning and sizing your GUI elements by hand
Now, you write code for the Form Resize event and set top, left and size of all your GUI elements by hand. That are three statements for every element and again for the two possible orientations. Having only four elements on your form, that will be 24 lines to code! Stupid coding, I thought and remembered the LMs available for JAVA. So I tried to find JAVA-like layout managers for DotNet. First, I did not find any, as the full framework already provides a LM and knowone seems to have a need for writing there own LM. But finally I found three LMs in the internet.
What is the purpose of a layout manager
A LM should arrange GUI elements inside a container (a form or dialog) according to some well known layout pattern. Instead of writing many code lines to position and resize your GUI elements, the LM will do this for you and place and size the elements according to the LMs rules. Of course you have to write additional statements to get an automatic layout, but you need only write once and it will work for portrait and landscape orientation.
Coding
All the LMs I found work similar. You have to add a container, possibly specify a layout, and then add your GUI elements to the LM.
The layout of your GUI elements
There are different layouts available:
- Flow Layout – positions GUI elements like written text, from left to right and top to bottom
- Table or Grid Layout – provides a table of cells in rows and columns. Each element is added to the next free cell
- Border Layout – the available space is devided into 5 zones, north, west, center, east and south. You can have one element (also containers with several elements) at each of these locations
The Layout Managers I found
- Drop-dead easy LM (Link) (no further use here)
- Grid Layout (Link) (no further use here, uses OnLayout)
- Single Column FlowLayout (Link)(no further use here)
- Layout Managers in C# (Link)(great compact framework compatible LM), local copy
- Simple Layout Managers (Link)(looks also impressive)
- FlowLayoutPanel for CF (Link)(This was the first one I found in the net)
- DotNetLayout (SourceForge Link)
- GridLayout (Link)(easy to use GridLayout Manager, I only miss RowSpan feature)
Be aware of compact framework does not support OnLayout event. So some of the LMs listed above are not comaptible with CF.
Sample Codes
Example 1 using LayoutManagers
using System;
using System.Drawing;
using System.Windows.Forms;
using Layout;
namespace PanelTest2
{
public class DialogTest : Form
{
AreaPane panel;
Button button;
Button btn_Size;
TextBox textbox;
Label label;
PictureBox picturebox;
Panel panel1;
public DialogTest ()
{
this.SuspendLayout();
this.Text="PanelTest";
panel = new ResizeablePane(this, ClientRectangle, new BorderLayout());
#region north
Panel panelNorth=new Panel();
ContainerBox boxNorth=new ContainerBox(panelNorth);
label=new Label(); label.Name="label";
label.Text="Label:";
label.Top=26; label.Left=26;
label.Size=new Size(100, 26);
boxNorth.LayoutManager=new GridLayout(1,2);
boxNorth.Add(label);//, BorderLayout.Direction.East);
textbox=new TextBox(); textbox.Name="textbox";
textbox.Left=150; textbox.Top=26;
textbox.Size=new Size(100, 26);
boxNorth.Add(textbox);//, BorderLayout.Direction.West);
#endregion
#region south
Panel panelSouth=new Panel();
ContainerBox boxSouth=new ContainerBox(panelSouth);
button= new Button(); button.Name="button";
button.Location=new Point(26,84);
button.Size=new Size(52,26);
button.Text="Exit";
button.Click+=new System.EventHandler(this.button_clicked);
btn_Size=new Button(); btn_Size.Name="btn_size";
btn_Size.Location=new Point(108,84);
btn_Size.Size=new Size(52,26);
btn_Size.Text="Resize";
btn_Size.Click+=new System.EventHandler(this.btn_Size_clicked);
Button btnTest=new Button();
btnTest.Text="Test";
btnTest.Click += new EventHandler(btnTest_Click);
boxSouth.LayoutManager=new GridLayout(1,3);
boxSouth.Add(btnTest);
boxSouth.Add(btn_Size);//, BorderLayout.Direction.East);
boxSouth.Add(button);//, BorderLayout.Direction.East);
#endregion
#region center
Panel panelCenter=new Panel();
ContainerBox boxCenter=new ContainerBox(panelCenter);
boxCenter.LayoutManager=new GridLayout(1,2);
panel1=new Panel(); panel1.Name="panel1";
panel1.BackColor=Color.Pink;
panel1.Top=26;
panel1.Left=180;
panel1.Size=new Size(26,100);
picturebox=new PictureBox(); picturebox.Name="picturebox";
picturebox.BackColor=Color.Azure;
picturebox.ForeColor=Color.Red;
picturebox.Size=new Size(26,84);
picturebox.Left=108;
picturebox.Top=168;
boxCenter.Add(panel1);
boxCenter.Add(picturebox);
#endregion
panel.Add(boxSouth, BorderLayout.Direction.South);
panel.Add(boxNorth, BorderLayout.Direction.North);
panel.Add(boxCenter, BorderLayout.Direction.Center);
this.ResumeLayout(true);
}
The code above will produce this automatic layout:
In the above code all GUI elements are created and sized manually. You can also design your Form with the Form designer in Visual Studio and then add the existing elements to the layout panels. But dont use foreach with the form elements, as the order is reversed or unwanted.
The code sample shows how to use a BorderLayout, panels to group elements and nesting layouts using a different LM like a grid layout.
Example 2 using GridLayout
...
using LayoutManagers; // http://dnetgridlayout.sourceforge.net/
public partial class Form1 : Form
{
//PanelWithLayout panelWithLayout1;
TextBox txtBox1;
TextBox txtBox2;
Button btnTest;
public Form1()
{
InitializeComponent();
//Create a layout with 0 rows and 2 columns
GridLayout myGridlayout = new GridLayout(0, 2, true);
//the spacing between the elements
myGridlayout.intHorizontalSpacing = 4;
//the elements width should fill the column
myGridlayout.bFillColumn = true;
myGridlayout.dblRequiredHeight = 26;
panelWithLayout1.AutoScroll = true;
panelWithLayout1.setLayout(myGridlayout);
txtBox1 = new TextBox();
txtBox1.Width = panelWithLayout1.Width / 2;
txtBox1.Height = 26;
txtBox2 = new TextBox();
txtBox2.Width = panelWithLayout1.Width / 2;
txtBox2.Height = 26;
//add a text box (in first row, as long as they fit)
panelWithLayout1.addControl(txtBox1);
//add a button
btnTest = new Button();
btnTest.Height = 26;
btnTest.Width = panelWithLayout1.Width / 2;
btnTest.Text = "Test";
panelWithLayout1.addControl(btnTest);
//add the button click event handler
btnTest.Click += new EventHandler(btnTest_Click);
//add the existing datagrid1 (see designer) spanning 2 columns
dataGrid1.Width = panelWithLayout1.Width;
dataGrid1.Height = panelWithLayout1.Height/3;
//add another textbox
panelWithLayout1.addControl(txtBox2);
}
...
Here are the screens of the gridLayout Test
As you can see, this also easy to use.
Example 3 also using GridLayout
This example uses the already available GUI elements of a form designed with VS2005 visual designer. So, this time you dont have to set sizes or positions, just add the existing GUI elements.
... public start_frm() { InitializeComponent(); this.SuspendLayout(); ResizeablePane LayoutPanel = new ResizeablePane(this, ClientRectangle, new GridLayout(0, 1, 4, 4)); LayoutPanel.Add(btn_barcode); LayoutPanel.Add(btn_camera); LayoutPanel.Add(btnMSCamera); LayoutPanel.Add(btnSignature); LayoutPanel.Add(btnExit); LayoutPanel.Add(sStatusPos); LayoutPanel.Add(status); LayoutPanel.Add(lblVersion); this.ResumeLayout(true); ...
Here is the portrait screen view of the above code:
Conclusion
If you ever need to design GUIs for mobile devices with automatic portrait and landscape switching consider to use one of the Layout Managers available.